﻿using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System;
using System.Web;
using System.Drawing.Text;

namespace CaptchaControl
{
     class CaptchaImage
    {
        #region Public Properties 

        /// <summary>
        /// Draw width of the image
        /// </summary>
        public int DrawWidth
        {
            get
            {
                return _drawWidth;
            }
            set
            {
                _drawWidth = value;
            }
        }
        
        /// <summary>
        /// Draw height of image
        /// </summary>
        public int DrawHeight
        {
            get
            {
                return _drawHeight;
            }
            set
            {
                _drawHeight = value;
            }
        }

        /// <summary>
        /// Number of the characters to be shown
        /// </summary>
        public int NumberOfChars
        {
            get
            {
                return _numberOfChars;
            }
            set
            {
                _numberOfChars = value;
            }
        }

        /// <summary>
        /// Unique Id for this captcha control
        /// </summary>
        public string UniqueID
        {
            get
            {
                return _uniqueID;
            }
            set
            {
                _uniqueID = value;
            }
        }

        /// <summary>
        /// Code to be printed on the image
        /// </summary>
        public string CaptchaCode
        {
            get
            {
                return _captchaCode;
            }
            set
            {
                _captchaCode = value;
            }
        }

        #endregion

        #region Public Methods

        public CaptchaImage()
        {
            string captchaID = GetUniqueID();
            _uniqueID = captchaID;
        }

        /// <summary>
        /// Gets the cached captcha.
        /// </summary>
        /// <param name="guid">The GUID.</param>
        /// <returns></returns>
        public static CaptchaImage GetCachedCaptcha(string guid)
        {
            if (String.IsNullOrEmpty(guid))
                return null;

            return (CaptchaImage)HttpRuntime.Cache.Get(guid);
        }

        /// <summary>
        /// Generate the captcha image
        /// </summary>
        /// <returns>Captcha Image</returns>
        public Bitmap GenerateCaptcha()
        {
            return GenerateImage();
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Generate the captcha output image
        /// </summary>
        /// <param name="captchaCode"></param>
        /// <returns></returns>
        private Bitmap GenerateImage()
        {
            string captchaCode = GetCaptchaCode();
            _captchaCode = captchaCode;

            Bitmap bmp = new Bitmap(_drawWidth, _drawHeight,
                PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            Rectangle rect = new Rectangle(0, 0, _drawWidth, _drawHeight);


            HatchBrush brush = new HatchBrush(
              HatchStyle.Weave,
              Color.WhiteSmoke,
              Color.White);
            g.FillRectangle(brush, rect);

            //g.DrawString(captchaCode,
            //    new Font("Tahoma", 20.0f, FontStyle.Bold),
            //    Brushes.Black, new PointF(0, 0));

            int[] TextColor = new int[] { 200, 200, 200 };// The 3 numbers represent in order RED, GREEN, BLUE
            SolidBrush letterBrush = default(SolidBrush);
            Random ranRotate = new Random();
            bool RandomTextColor = true;// True / False. If you choose True, TextColor will not apply 
            if (RandomTextColor == true)
            {
                letterBrush = new SolidBrush(Color.FromArgb((ranRotate.Next(0, 255)), (ranRotate.Next(0, 255)), (ranRotate.Next(0, 255))));
            }
            else
            {
                letterBrush = new SolidBrush(Color.FromArgb(TextColor[0], TextColor[1], TextColor[2]));
            }

            
            System.Drawing.Drawing2D.Matrix matRotate = new System.Drawing.Drawing2D.Matrix();
            int i = 0;

            for (i = 0; i <= captchaCode.Length - 1; i++)
            {
                int intChars = captchaCode.Length;
                int x = _drawWidth / (intChars + 1) * i;
                int y = _drawHeight / 2;
                //matRotate.RotateAt(ranRotate.Next(-5, 5), new PointF(x / (intChars + 1) * i, y * 1/ranRotate.Next(1,4)));
                matRotate.RotateAt(ranRotate.Next(-5, 5), new PointF(x, y));
                g.Transform = matRotate;
                int fontSize = _drawHeight / 3;
                if (i == 0)
                {
                    //draw ‘the text on our image
                    //graCanvas.DrawString(strText.Chars(i), new Font("Comic Sans MS", 25, FontStyle.Italic), letterBrush, width / (intChars + 1) * i, height * 0.4);
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Comic Sans MS", fontSize, FontStyle.Italic), letterBrush, _drawWidth / (intChars + 10), 20);
                }
                else if (i == 1)
                {
                    //draw ‘the text on our image
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Arial", fontSize+5, FontStyle.Bold), letterBrush, _drawWidth / (intChars + 1) * i, 5);
                }
                else if (i == 2)
                {
                    //draw ‘the text on our image
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Times New Roman", fontSize, FontStyle.Italic), letterBrush, _drawWidth / (intChars + 1) * i, 20);
                }
                else if (i == 3)
                {
                    //draw ‘the text on our image
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Georgia", fontSize+5, FontStyle.Bold), letterBrush, _drawWidth / (intChars + 1) * i, 5);
                }
                else if (i == 4)
                {
                    //draw ‘the text on our image
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Verdana", fontSize, FontStyle.Italic), letterBrush, _drawWidth / (intChars + 1) * i, 20);
                }
                else if (i == 5)
                {
                    //draw ‘the text on our image
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Geneva", fontSize+5, FontStyle.Bold), letterBrush, _drawWidth / (intChars + 1) * i, 5);
                }
                else
                {
                    //draw ‘the text on our image
                    g.DrawString(captchaCode.Substring(i, 1), new Font("Verdana", fontSize, FontStyle.Italic), letterBrush, _drawWidth / (intChars + 1) * i, 20);
                }
                g.ResetTransform();
            }

            //Aniade ruido a la imagen
            //AddNoise(g);
            //DrawRandomLines(g);
            return bmp;
        }

        private void AddNoise(Graphics g)
        {
            Random rand = new Random();

            for (int i = 1; i < 5; i++)
            {
                int posX = rand.Next(1, _drawWidth);
                int posY = rand.Next(1, _drawHeight);
                int width = rand.Next(100);
                int height = rand.Next(100);
                g.DrawEllipse(Pens.Gray, posX , posY,
                    width, height);

               
            }
        }

        private void DrawRandomLines(Graphics g)
        {
            SolidBrush green = new SolidBrush(Color.Gray);

            for (int i = 0; i < 150; i++)
            {
                g.DrawLines(new Pen(green, 2), GetRandomPoints());
            }

        }

        private Point[] GetRandomPoints()
        {
            Random rand = new Random();
            Point[] points = { new Point(rand.Next(5, 50), 
                       rand.Next(5, 30)), 
                       new Point(rand.Next(5, 50), 
                       rand.Next(5, 50)) };
            return points;
        }

        public string fncDrawCaptcha(string path)
        {

            //*** Editable Values
            int[] BackgroundColor = new int[] { 255, 255, 255 };// The 3 numbers represent in order RED, GREEN, BLUE for the captcha's background color
            bool RandomBackgroundNoiseColor = true;// True / False. If you choose True, BackgroundNoiseColor will not apply 
            bool RandomTextColor = true;// True / False. If you choose True, TextColor will not apply 
            int[] BackgroundNoiseColor = new int[] { 150, 150, 150 };// The 3 numbers represent in order RED, GREEN, BLUE
            int[] TextColor = new int[] { 200, 200, 200 };// The 3 numbers represent in order RED, GREEN, BLUE
            HatchStyle BackgroundNoiseTexture = HatchStyle.Min;// replace ".Min" with any of the following: Horizontal, Vertical, ForwardDiagonal, BackwardDiagonal, Cross, DiagonalCross, Percent05, Percent10, Percent20, Percent25, Percent30, Percent40, Percent50, Percent60, Percent70, Percent75, Percent80, Percent90, LightDownwardDiagonal, LightUpwardDiagonal, DarkDownwardDiagonal, DarkUpwardDiagonal, WideDownwardDiagonal, WideUpwardDiagonal, LightVertical, LightHorizontal, NarrowVertical, NarrowHorizontal, DarkVertical, DarkHorizontal, DashedDownwardDiagonal, DashedUpwardDiagonal, DashedHorizontal, DashedVertical, SmallConfetti, LargeConfetti, ZigZag, Wave, DiagonalBrick, HorizontalBrick, Weave, Plaid, Divot, DottedGrid, DottedDiamond, Shingle, Trellis, Sphere, SmallGrid, SmallCheckerBoard, LargeCheckerBoard, OutlinedDiamond, SolidDiamond, LargeGrid, Min, Max
            int length = 6;// Number of characters to generate
            //*** END Editable Values

            int height = 80;
            int width = 160;
            width = width + ((length - 6) * 30);
            Random ranRotate = new Random();

            string strText = System.Guid.NewGuid().ToString();
            strText = strText.Replace("-", String.Empty);
            strText = strText.Substring(0, length);

            Bitmap bmpCanvas = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            Graphics graCanvas = Graphics.FromImage(bmpCanvas);
            RectangleF recF = new RectangleF(0, 0, width, height);
            Brush bruBackground = default(Brush);
            SolidBrush letterBrush = default(SolidBrush);

            graCanvas.TextRenderingHint = TextRenderingHint.AntiAlias;

            if (RandomBackgroundNoiseColor == true)
            {
                bruBackground = new HatchBrush(BackgroundNoiseTexture, Color.FromArgb((ranRotate.Next(0, 255)), (ranRotate.Next(0, 255)), (ranRotate.Next(0, 255))), Color.FromArgb(BackgroundColor[0], BackgroundColor[1], BackgroundColor[2]));
            }
            else
            {
                bruBackground = new HatchBrush(BackgroundNoiseTexture, Color.FromArgb(BackgroundNoiseColor[0], BackgroundNoiseColor[1], BackgroundNoiseColor[2]), Color.FromArgb(BackgroundColor[0], BackgroundColor[1], BackgroundColor[2]));
            }

            graCanvas.FillRectangle(bruBackground, recF);

            if (RandomTextColor == true)
            {
                letterBrush = new SolidBrush(Color.FromArgb((ranRotate.Next(0, 255)), (ranRotate.Next(0, 255)), (ranRotate.Next(0, 255))));
            }
            else
            {
                letterBrush = new SolidBrush(Color.FromArgb(TextColor[0], TextColor[1], TextColor[2]));
            }

            System.Drawing.Drawing2D.Matrix matRotate = new System.Drawing.Drawing2D.Matrix();
            int i = 0;
            for (i = 0; i <= strText.Length - 1; i++)
            {
                matRotate.Reset();
                int intChars = strText.Length;
                int x = width / (intChars + 1) * i;
                int y = height / 2;
                //matRotate.RotateAt(ranRotate.Next(-30, 30), new PointF(width / (intChars + 1) * i, height * 0.5) );
                matRotate.RotateAt(ranRotate.Next(-30, 30), new PointF(x, y));
                graCanvas.Transform = matRotate;
                if (i == 0)
                {
                    //draw ‘the text on our image
                    //graCanvas.DrawString(strText.Chars(i), new Font("Comic Sans MS", 25, FontStyle.Italic), letterBrush, width / (intChars + 1) * i, height * 0.4);
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Comic Sans MS", 25, FontStyle.Italic), letterBrush, width / (intChars + 1) * i, 40);
                }
                else if (i == 1)
                {
                    //draw ‘the text on our image
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Arial", 30, FontStyle.Bold), letterBrush, width / (intChars + 1) * i, 10);
                }
                else if (i == 2)
                {
                    //draw ‘the text on our image
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Times New Roman", 25, FontStyle.Italic), letterBrush, width / (intChars + 1) * i, 40);
                }
                else if (i == 3)
                {
                    //draw ‘the text on our image
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Georgia", 35, FontStyle.Bold), letterBrush, width / (intChars + 1) * i, 10);
                }
                else if (i == 4)
                {
                    //draw ‘the text on our image
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Verdana", 25, FontStyle.Italic), letterBrush, width / (intChars + 1) * i, 40);
                }
                else if (i == 5)
                {
                    //draw ‘the text on our image
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Geneva", 30, FontStyle.Bold), letterBrush, width / (intChars + 1) * i, 10);
                }
                else
                {
                    //draw ‘the text on our image
                    graCanvas.DrawString(strText.Substring(i, 1), new Font("Verdana", 25, FontStyle.Italic), letterBrush, width / (intChars + 1) * i, 40);
                }
                graCanvas.ResetTransform();
            }

            bmpCanvas.Save(path, ImageFormat.Gif);
            graCanvas.Dispose();
            bmpCanvas.Dispose();

            return strText;
        }


        /// <summary>
        /// Generate a unique id for the this control
        /// </summary>
        /// <returns></returns>
        private string GetUniqueID()
        {
            return Guid.NewGuid().ToString();
        }

        private string GetCaptchaCode()
        {
            Random rand = new Random();
            string code = "";
            int charLen = _charSet.Length;

            for (int i = 0; i < _numberOfChars; i++)
            {
                int pos = rand.Next(0,charLen);
                code += _charSet.Substring(pos, 1);
            }

            return code;
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Char set for generating Captcha Code
        /// </summary>
        private const string _charSet = "1234567890";

        private int _drawWidth = 200;

        private int _drawHeight = 50;

        private int _numberOfChars = 6;

        private string _uniqueID;

        private string _captchaCode;

        #endregion
    }
}
